defmodule Iocp.Sender do
  @moduledoc false

  use Bitwise

  @packet_start [0x68, 0x16]

  def send_adjust_time(client, device_address) do
    {{year, month, day}, {hour, minute, second}} = Timex.local()
                                                   |> DateTime.to_naive()
                                                   |> NaiveDateTime.to_erl()
    [device_address_lo, device_address_hi] = device_address |> to_little_endian()

    packet = pack([
      0,
      0x02,
      device_address_lo,
      device_address_hi,
      second, minute, hour, day, month, rem(year, 1000)
    ])

    :ok = :gen_tcp.send(client, packet)
  end

  def send_fetch_data(client, device_address) do
    {{year, month, day}, {hour, minute, second}} = Timex.local()
                                                   |> DateTime.to_naive()
                                                   |> NaiveDateTime.to_erl()
    [device_address_lo, device_address_hi] = device_address |> to_little_endian()

    packet = pack([
      0,
      0x03,
      device_address_lo,
      device_address_hi,
      second, minute, hour, day, month, rem(year, 1000),
      1,
      30
    ])
    
    :ok = :gen_tcp.send(client, packet)
  end

  defp pack(data) do
    data_length = length(data) + 1  # 1位校验码
    data = [@packet_start, to_little_endian(data_length), data]
    checksum = data |> Stream.flat_map(& &1) |> Enum.sum() |> Bitwise.&&&(0xFF)
    [data, checksum]
  end

  defp to_little_endian(n) when is_integer(n) do
    [
      n &&& 0xFF,
      (n &&& 0xFF00) >>> 8
    ]
  end
end
